import json
import pika
from decouple import config
from .models import *
from .cloud import CloudInstance
from datetime import date, datetime
from .serializer.experiment import InstanceListSerializer
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException

class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(obj, date):
            return obj.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, obj)

# 约定实训平台生产Key
queue_name = 'satptest_SatpTechnicalCourseDirectQueue'
routing_key = 'satptest_SatpTechnicalCourseDirectRouting'
exchange = 'satptest_SatpTechnicalCourseDirectExchange'
virtual_host = '/'

def send_data_to_rabbitmq(data, queue=queue_name, routing_key=routing_key,exchange=exchange, virtual_host=virtual_host):
  if data is None:
      return False
  # 建立和RabbitMQ的连接
  try:
      credentials = pika.PlainCredentials(config('EAX_MQ_USER'), config('EAX_MQ_PASS'))  # 两个参数：用户名和密码

      connection = pika.BlockingConnection(
        pika.ConnectionParameters(host=config("EAX_MQ_HOST"), port=int(config('EAX_MQ_PROT')), virtual_host=virtual_host, credentials=credentials)  # 四个参数：机器、端口、虚拟主机、认证信息
      )
      channel = connection.channel()
      # 声明交换机
      channel.exchange_declare(exchange=exchange, exchange_type='direct', durable=True)
      # 选择使用一个队列
      channel.queue_declare(queue=queue, durable=True)
      channel.queue_bind(exchange=exchange, queue=queue, routing_key=routing_key)
      # 发送一个消息
      channel.basic_publish(exchange=exchange, routing_key=routing_key, body=data)
      # 断开连接
      connection.close()
      return True
  except Exception as e:
      print(e)
      return False


# 实验课件同步数据格式（MQ同步）
# 说明：Technical平台实验数据发生变更，推送数据
# param action "add/update/delete其中一个",
def experiment_data_send(experiment_id, action='update'):
    experiment = Experiment.objects.filter(id=experiment_id).first()
    if experiment is None:
        return None

    teacher_names = ''
    user_ids = experiment.teacher.values_list('user_id')
    if user_ids is None:
        teacher_names = ''
    real_names = UserProfile.objects.filter(id__in=user_ids).values('real_name')
    if real_names is []:
        teacher_names = ''
    re = []
    for item in real_names:
        re.append(item['real_name'])

    if not re:
        teacher_names = ''
    else:
        teacher_names = ','.join(re)

    detail_type = 'Markdown'
    if experiment.detail_type == "H":
        detail_type = 'Html'

    environment = Environment.objects.filter(id=experiment.environment_id).first()
    if environment is None:
        return None

    describe_list = ExperimentChapter.objects.filter(experiment_id=experiment.id).values('detail')
    describe = []
    if describe_list is []:
        describe = ""
    else:
        for item in describe_list:
            describe.append(item['detail'])
        describe = json.dumps(describe)

    experiment_json = {
            "module": "experiment",
            "action": action,
            "data": {
                "id": experiment.id,
                "experiment_name": experiment.experiment_name,
                "detail_type": detail_type,
                "duration": experiment.duration,  #单位:分钟 实验持续时间，即学生主动开始实验后限制时长
                "vnccode": experiment.vnccode,## 含义 并说明都有哪些可能值
                "describe": describe,
                "type": experiment.type,  ## 含义 并说明都有哪些可能值 (choices=((2, 'free'), (3, 'purchase')), default=2)
                "price": experiment.price,
                "user_limit": experiment.user_limit,
                "user_count": experiment.student.count(),
                "intro": experiment.intro,
                "course_names": "",
                "teacher_names": teacher_names,
                "environment": {
                    "id": environment.id,
                    "environment_name": environment.environment_name,
                    "image": next(iter(environment.image.all().values('image_name'))) if environment.image.all() else None,
                    "subnet_name": environment.subnet_name,
                    "cidr_block": environment.cidr_block,
                    "is_open": environment.is_open,  ## 含义 并说明都有哪些可能值 ('T', 'True'), ('F', 'False')
                    "create_time": environment.create_time,
                    "security_group": environment.security_group
                },
              }
    }
    data = json.dumps(experiment_json, cls=ComplexEncoder)
    send_data_to_rabbitmq(data)
    return data

#实验课件数据初始化（MQ同步）
#说明：Technical平台接收到E安行平台的init指令，推送数据
def experiment_list_data_send():
    experiment_all = Experiment.objects.filter(status="N").all()

    if experiment_all.exists() is False:
        return None
    data = []
    for experiment in experiment_all:
        detail_type = 'Markdown'
        if experiment.detail_type == "H":
            detail_type = 'Html'

        teacher_names = ''
        user_ids = experiment.teacher.values_list('user_id')
        if user_ids is None:
            teacher_names = ''
        real_names = UserProfile.objects.filter(id__in=user_ids).values('real_name')
        if real_names is []:
            teacher_names = ''
        re = []
        for item in real_names:
            re.append(item['real_name'])

        if not re:
            teacher_names = ''
        else:
            teacher_names = ','.join(re)

        environment = Environment.objects.filter(id=experiment.environment_id).first()
        if environment is None:
            continue

        describe_list = ExperimentChapter.objects.filter(experiment_id=experiment.id).values('detail')
        describe = []
        if describe_list is []:
            describe = ""
        else:
            for item in describe_list:
                describe.append(item['detail'])
            describe = json.dumps(describe)
        data.append({
            "id": experiment.id,
            "experiment_name": experiment.experiment_name,
            "detail_type": detail_type,
            "duration": experiment.duration,  # 单位:分钟 实验持续时间，即学生主动开始实验后限制时长
            "vnccode": experiment.vnccode,  ## 含义 并说明都有哪些可能值
            "describe": describe,
            "type": experiment.type,  ## 含义 并说明都有哪些可能值 (choices=((2, 'free'), (3, 'purchase')), default=2)
            "price": experiment.price,
            "user_limit": experiment.user_limit,
            "user_count": experiment.student.count(),
            "intro": experiment.intro,
            "course_names": "",
            "teacher_names": teacher_names,
            "environment": {
                "id": environment.id,
                "environment_name": environment.environment_name,
                "image": str(environment.image.all()[0]),
                "subnet_name": environment.subnet_name,
                "cidr_block": environment.cidr_block,
                "is_open": environment.is_open,  ## 含义 并说明都有哪些可能值 ('T', 'True'), ('F', 'False')
                "create_time": environment.create_time,
                "security_group": environment.security_group
            },
        })

    if not data:
        return None
    experiment_list_json = {
        "module": "experiment",
        "action": "init",
        "data": data
    }
    res = json.dumps(experiment_list_json, cls=ComplexEncoder)
    send_data_to_rabbitmq(res)
    return res

# 实验虚机实例同步（MQ同步）
#说明：Technical平台实例数据发生变更，推送数据
# param action "create/start/shutdown/delete/其中一个"
def virtual_data_send(request, experiment_id, action='create'):

    eax_user_jsonstr = request.COOKIES.get('EAX_USER_INFO')

    print("*****************************")
    print(eax_user_jsonstr)
    print("*****************************")

    if eax_user_jsonstr is None or eax_user_jsonstr == "None" or eax_user_jsonstr == '':
        return None
    eax_user = json.loads(eax_user_jsonstr)

    experiment = Experiment.objects.filter(id=experiment_id).first()
    if experiment is None:
        return None
    environment = Environment.objects.filter(id=experiment.environment_id).first()
    if environment is None:
        return None

    instance = Instance.objects.filter(environment_id=environment.id).first()
    if instance is None:
        return None

    StatusLabel = {
        'N': '已运行',
        'K': '已开机',
        'S': '已关机',
        'C': '已销毁'
    }

    status = 'N'
    if action == 'start':
        status = 'K'
    if action == 'create':
        status = 'N'
    if action == 'shutdown':
        status = 'S'
    if action == 'delete':
        status = 'C'

    if status == 'C':
        vnc_url = ''
    else:
        vnc_url = get_vnc_url(instance)

    virtual_json = {
        "module": "instance",
        "action": action,
        "data": {
            "experiment_id": experiment.id,
            # 新加数据
            "user_id": eax_user['user_id'],  # 用户ID
            "user_tenant": eax_user['user_tenant'],  # 用户所属租户（客户）通过redis同步
            "task_id": eax_user['task_id'],  # 活动ID Lo 通过redis同步
            "courseware_id": eax_user['courseware_id'],
            "instance": {
                "ImageId": instance.image.id,
                "ImageName": instance.image.image_name,
                "OsName": instance.image.opration_system,
                "Arc": instance.image.architecture,
                "PrivateIpAddresses": instance.private_ip_address,
                "PublicIpAddresses": instance.ip_address,
                "Name": instance.name,
                "Status": status, # ('N', 'Normal'), ('S', 'Shutdown'), ('C', 'Canceled')
                "StatusLabel": StatusLabel[status],
                "InsId": instance.instanceId,
                "vnc_url": vnc_url
            }
        }
    }

    data = json.dumps(virtual_json)
    send_data_to_rabbitmq(data)
    return data

def get_vnc_url(obj):
    cloudInstance = CloudInstance()
    try:
        vncUrl = cloudInstance.DescribeInstanceVncUrl(obj.instanceId)
    except TencentCloudSDKException as e:
        vncUrl = ''
    return vncUrl

#实验操作记录数据格式（MQ同步）
#说明：Technical平台实例数据发生变更，推送数据
# action 创建实例create、开始实验start、结束实验end
# param action "create/start/shutdown/delete/其中一个"
def study_record_data_send(request, experiment_id, instance_id, action='create'):
    eax_user_jsonstr = request.COOKIES.get('EAX_USER_INFO')

    print("*****************************")
    print(eax_user_jsonstr)
    print("*****************************")

    if eax_user_jsonstr is None or eax_user_jsonstr == "None" or eax_user_jsonstr == '':
        return None

    eax_user = json.loads(eax_user_jsonstr)
    action_note = {
        'create': '创建实例',
        'start': '开机开始实验',
        'shutdown': '关机结束实验',
        'delete': '回收实例'
    }
    course_id = eax_user.get('course_id', None)
    class_user_courseware_id = eax_user.get('class_user_courseware_id', '')
    if course_id is None:
        study_record_json = {
                "module": "studyRecord",
                "action": action,
                "data": {
                    "user_phone": eax_user['user_phone'],  # 用户手机号通过redis同步,user_tenant和user_phone唯一确定一个用户
                    "user_id": eax_user['user_id'],  # 用户ID
                    "user_tenant": eax_user['user_tenant'],  # 用户所属租户（客户）通过redis同步
                    "task_id": eax_user['task_id'],  # 活动ID Lo 通过redis同步
                    "experiment_id": experiment_id,
                    "courseware_id": eax_user['courseware_id'],
                    "class_user_courseware_id": class_user_courseware_id,
                    "task_type": eax_user['task_type'],
                    "instance_id": instance_id,
                    "action": action_note[action],
                    "action_time": datetime.now()
                }
        }
    else:
        study_record_json = {
            "module": "studyRecord",
            "action": action,
            "data": {
                "user_phone": eax_user['user_phone'],  # 用户手机号通过redis同步,user_tenant和user_phone唯一确定一个用户
                "user_id": eax_user['user_id'],  # 用户ID
                "user_tenant": eax_user['user_tenant'],  # 用户所属租户（客户）通过redis同步
                "task_id": eax_user['task_id'],  # 活动ID Lo 通过redis同步
                "experiment_id": experiment_id,
                "course_id": eax_user['course_id'],
                "courseware_id": eax_user['courseware_id'],
                "class_user_courseware_id": class_user_courseware_id,
                "task_type": eax_user['task_type'],
                "instance_id": instance_id,
                "action": action_note[action],
                "action_time": datetime.now()
            }
        }

    data = json.dumps(study_record_json,  cls=ComplexEncoder)
    send_data_to_rabbitmq(data)
    print("*****************************")
    print(study_record_json)
    print("*****************************")
    return data
